#include "XMLer.h"
#include <QVariant>
#include <QTextStream>
#include <QDomNodeList>
//#include "./XXlogger.h"

XMLer::XMLer(QObject *parent) : QObject(parent)
{
    _file = nullptr;
}
XMLer::~XMLer(){
    close();
}

void XMLer::open(const QString &filePath, bool create){
    if(_file){
        //xxLog("could not open file again.");
        return;
    }
    _file.reset(new QFile(filePath));
    if(!_file->exists()){
        if(create){
            _file->open(QIODevice::ReadWrite|QIODevice::NewOnly);
        }
        else{
            //xxLog("file is not exists.");
            _file = nullptr;
            return;
        }
    }
    else {
        _file->open(QIODevice::ReadWrite);
    }

    _doc.setContent(_file.data());
}
void XMLer::openFromString(const QString &content){
    _doc.setContent(content.toUtf8());
}
void XMLer::close(){
    if(!_file){
        return;
    }
    _file->close();
    _file = nullptr;
}

void XMLer::writeString(QStringList path, QString value){
    QDomNode node = findChild(_doc,path,true);
    saveNodeValue(node,value);
    saveToFile();
}
void XMLer::writeMap(QStringList path, QVariantMap value){
    QDomNode node = findChild(_doc,path,true);
    saveNodeValue(node,value);
    saveToFile();
}

QString XMLer::readString(QStringList path){
    QDomNode node = findChild(_doc,path,false);
    if(node.isNull() || !node.hasChildNodes()){
        return "";
    }
    else{
        return node.firstChild().nodeValue();
    }
}
QVariantMap XMLer::readMap(QStringList path){
    QDomNode node = findChild(_doc,path,false);
    return getNodeValue(node).toMap();
}
QVariantList XMLer::readList(QStringList path){
    QDomNode node = findChild(_doc,path,false);
    auto children = node.childNodes();
    QVariantList list;
    for (int index=0; index<children.count(); index++) {
        QDomNode child = children.at(index);
        list << getNodeValue(child).toMap();
    }
    return list;
}

QVariant XMLer::getNodeValue(QDomNode &node){
    auto children = node.childNodes();
    if(children.isEmpty()){
        return QVariant();
    }
    if(1==children.count()){
        if(children.at(0).isText()){
            return children.at(0).nodeValue();
        }
        else{
            return QVariant();
        }
    }
    else{
        QVariantMap map;
        for (int index=0; index<children.count(); index++) {
            auto child = children.at(index);
            if(!child.hasChildNodes() || 1!=child.childNodes().count()){
                continue;
            }
            map[child.toElement().tagName()] = child.firstChild().nodeValue();
        }
        return map;
    }
}
void XMLer::saveNodeValue(QDomNode &node, QVariant value){
    if(value.canConvert<QString>()){
        saveStringToNode(node,value.toString());
    }
    else if(value.canConvert<QMap<QString,QString>>()){
        QVariantMap map = value.toMap();
        for (auto iter=map.begin(); iter!=map.end(); iter++) {
            saveMapToNode(node,iter.key(),iter.value().toString());
        }
    }
    else{

    }
}
void XMLer::saveMapToNode(QDomNode &node, QString key, QString value){
    auto child = node.firstChildElement(key);
    if(child.isNull()){
        child = _doc.createElement(key);
        node.appendChild(child);
    }
    saveNodeValue(child,value);
}
void XMLer::saveStringToNode(QDomNode &node, QString value){
    if(node.hasChildNodes()){
        node.setNodeValue(value);
    }
    else{
        auto t = _doc.createTextNode(value);
        node.appendChild(t);
    }
}
void XMLer::saveToFile(){
    if(!_file){
        return;
    }
    _file->close();
    _file->open(QIODevice::ReadWrite|QIODevice::Truncate);
    QTextStream out(_file.data());
    out.setCodec("UTF-8");
    _doc.save(out, 4, QDomNode::EncodingFromTextStream);
}

QDomNode XMLer::findChild(QDomNode &node, QStringList path, bool create){
    QDomNode child = node;
    foreach(QString key, path){
        int i = -99;
        if(key.contains('.')){
            QStringList l = key.split('.');
            key = l[0];
            i = l[1].toInt();
        }

        if(i>=0){
            child = findChild(child,key,i,create);
        }
        else{
            child = findChild(child,key,create);
        }

        if(child.isNull()){
            break;
        }
    }
    return child;
}
QDomNode XMLer::findChild(QDomNode &node, const QString &childName, int index,  bool create){
    auto list = node.childNodes();
    if(index>=list.size() && !create){
        return QDomElement();
    }
    if(index==list.size() && create){
        QDomElement child = _doc.createElement(childName);
        node.appendChild(child);
        return child;
    }
    if(index>=0 && index<list.size()){
        return list.at(index).toElement();
    }
    return QDomElement();
}
QDomNode XMLer::findChild(QDomNode &node, const QString &childName, bool create){
    QDomElement child = node.firstChildElement(childName);
    if(child.isNull() && create){
        child = _doc.createElement(childName);
        node.appendChild(child);
    }
    return child;
}
